package com.xy.service.approval;

import com.xy.api.exception.BizException;
import com.xy.api.model.dto.approval.ApprovalTemplateDTO;
import com.xy.api.model.dto.approval.ApprovalTemplateInfoFieldDTO;
import com.xy.api.model.dto.approval.ApprovalTemplateNodeDTO;
import com.xy.api.model.request.approval.ApprovalTemplateRequest;
import com.xy.api.model.response.R;
import com.xy.api.model.response.Rows;
import com.xy.api.service.approval.IApprovalTemplateService;
import com.xy.mapper.approval.*;
import com.xy.model.po.approval.*;
import com.xy.utils.CustomBeanUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class ApprovalTemplateServiceImpl implements IApprovalTemplateService {

    @Autowired
    private ApprovalTemplateMapper approvalTemplateMapper;

    @Autowired
    private ApprovalTemplateNodeMapper approvalTemplateNodeMapper;

    @Autowired
    private ApprovalTemplateInfoFieldMapper approvalTemplateInfoFieldMapper;

    @Autowired
    private ApprovalTemplateNodeAuditorMapper approvalTemplateNodeAuditorMapper;

    @Autowired
    private ApprovalInstanceMapper approvalInstanceMapper;

    @Override
    public ApprovalTemplateDTO findById(Long id) {
        ApprovalTemplateDTO approvalTemplate = new ApprovalTemplateDTO();

        ApprovalTemplatePO approvalTemplatePO = approvalTemplateMapper.findById(id);
        if (null == approvalTemplatePO) {
            return null;
        }
        CustomBeanUtil.copyProperties(approvalTemplatePO, approvalTemplate);
        return approvalTemplate;
    }

    @Override
    public ApprovalTemplateDTO findDetailById(Long id) {
        ApprovalTemplateDTO approvalTemplate = findById(id);

        List<ApprovalTemplateInfoFieldPO> templateInfoFieldPOList = approvalTemplateInfoFieldMapper.findListByApprovalTemplateId(id);
        approvalTemplate.setApprovalTemplateInfoFieldList(CustomBeanUtil.copyListProperties(templateInfoFieldPOList, ApprovalTemplateInfoFieldDTO::new));

        List<ApprovalTemplateNodePO> templateNodePOList = approvalTemplateNodeMapper.findListByApprovalTemplateId(id);
        try {
            approvalTemplate.setApprovalTemplateNodes(getApprovalTemplateNodeDTO(templateNodePOList));
        } catch (Exception ex) {
            log.error("findDetailById -- setApprovalTemplateNodes 异常", ex);
        }
        if (!CollectionUtils.isEmpty(templateNodePOList)) {
            Set<Long> approvalTemplateIdSet = templateNodePOList.stream().map(e -> e.getId()).collect(Collectors.toSet());
            List<ApprovalTemplateNodeAuditorPO> approvalTemplateNodeAuditorPOList = approvalTemplateNodeAuditorMapper.findByApprovalTemplateId(id);
            Map<Long, List<ApprovalTemplateNodeAuditorPO>> templateNodeAuditorMap = approvalTemplateNodeAuditorPOList.stream().filter(e -> approvalTemplateIdSet.contains(e.getApprovalTemplateNodeId())).collect(Collectors.groupingBy(e -> e.getApprovalTemplateNodeId()));

            ApprovalTemplateNodeDTO nextNode = approvalTemplate.getApprovalTemplateNodes();
            while (null != nextNode) {
                Long nodeId = nextNode.getId();
                if (templateNodeAuditorMap.containsKey(nodeId)) {
                    List<ApprovalTemplateNodeAuditorPO> nodeAuditorPOList = templateNodeAuditorMap.get(nodeId);
                    //todo 将节点关联的用户塞入

                }
                nextNode = nextNode.getNextNode();
            }
        }
        return approvalTemplate;
    }

    /**
     * 将平铺的节点转为链表结构
     *
     * @param list
     * @return
     */
    private ApprovalTemplateNodeDTO getApprovalTemplateNodeDTO(List<ApprovalTemplateNodePO> list) throws Exception {
        if (CollectionUtils.isEmpty(list)) {
            return null;
        }
        ApprovalTemplateNodeDTO headNode = null;
        List<ApprovalTemplateNodeDTO> nodeList = CustomBeanUtil.copyListProperties(list, ApprovalTemplateNodeDTO::new);

        Map<Long, ApprovalTemplateNodeDTO> nodeMap = nodeList.stream().collect(Collectors.toMap(e -> e.getId(), e -> e));
        for (ApprovalTemplateNodeDTO approvalTemplateNode : nodeList) {
            Long parentId = approvalTemplateNode.getParentId();
            if (Objects.equals(parentId, -1l)) {
                headNode = approvalTemplateNode;
            } else {
                if (!nodeMap.containsKey(parentId)) {
                    throw new Exception("审批模板节点异常");
                }
                if (null != nodeMap.get(parentId)) {
                    throw new Exception("审批模板节点异常");
                }
                nodeMap.get(parentId).setNextNode(approvalTemplateNode);
            }
        }
        return headNode;
    }

    @Override
    public void edit(ApprovalTemplateDTO approvalTemplate) {
        Long approvalTemplateId = approvalTemplate.getId();
        checkApprovalTemplate(approvalTemplate);
        if (null == approvalTemplateId) {
            createApprovalTemplate(approvalTemplate);
        } else {
            updateApprovalTemplate(approvalTemplate);
        }
    }

    /**
     * 编辑活动通知时的校验
     *
     * @param approvalTemplate
     */
    private void checkApprovalTemplate(ApprovalTemplateDTO approvalTemplate) {
        Assert.notNull(approvalTemplate, "审批模板不能为空");
        Assert.notNull(approvalTemplate.getApprovalTemplateNodes(), "审批节点不能为空");
        Assert.hasText(approvalTemplate.getTemplateName(), "审批模板名称不能为空");

        ApprovalTemplateNodeDTO nextNode = approvalTemplate.getApprovalTemplateNodes();
        while (nextNode != null) {
            List<Long> auditorIdList = nextNode.getAuditorIdList();
            if (CollectionUtils.isEmpty(auditorIdList)) {
                throw new BizException("审批节点关联的用户不能为空");
            }
            nextNode = nextNode.getNextNode();
        }
    }

    @Transactional
    private void createApprovalTemplate(ApprovalTemplateDTO approvalTemplate) {
        //模板信息
        Long approvalTemplateId = insertApprovalTemplate(approvalTemplate);

        createTemplateWithId(approvalTemplateId, approvalTemplate);
    }

    /**
     * 创建模板的关联信息
     *
     * @param approvalTemplateId 模板ID
     * @param approvalTemplate   模板关联信息：t_approval_template_info_field、t_approval_template_node_auditor、t_approval_template_node
     */
    private void createTemplateWithId(Long approvalTemplateId, ApprovalTemplateDTO approvalTemplate) {
        //模板审批节点
        ApprovalTemplateNodeDTO next = approvalTemplate.getApprovalTemplateNodes();
        next.setParentId(-1l);
        do {
            next.setApprovalTemplateId(approvalTemplateId);
            Long nodeId = insertApprovalTemplateNode(next);

            //模板节点关联的用户
            List<Long> auditorIdList = next.getAuditorIdList();
            if (!CollectionUtils.isEmpty(auditorIdList)) {
                List<ApprovalTemplateNodeAuditorPO> approvalTemplateNodeAuditorPOList = new ArrayList<>();
                for (Long auditorId : auditorIdList) {
                    ApprovalTemplateNodeAuditorPO auditorPO = new ApprovalTemplateNodeAuditorPO();
                    auditorPO.setApprovalTemplateId(approvalTemplateId);
                    auditorPO.setApprovalTemplateNodeId(nodeId);
                    auditorPO.setUserId(auditorId);
                    approvalTemplateNodeAuditorPOList.add(auditorPO);
                }
                approvalTemplateNodeAuditorMapper.batchInsert(approvalTemplateNodeAuditorPOList);
            }

            if (null != (next = next.getNextNode())) {
                next.setParentId(nodeId);
            }
        } while (null != next);

        //模板信息项
        if (!CollectionUtils.isEmpty(approvalTemplate.getApprovalTemplateInfoFieldList())) {
            List<ApprovalTemplateInfoFieldDTO> approvalTemplateInfoFieldList = approvalTemplate.getApprovalTemplateInfoFieldList();
            approvalTemplateInfoFieldList.forEach(e -> e.setApprovalTemplateId(approvalTemplateId));

            List<ApprovalTemplateInfoFieldPO> approvalTemplateInfoFieldPOS = CustomBeanUtil.copyListProperties(approvalTemplateInfoFieldList, ApprovalTemplateInfoFieldPO::new);
            approvalTemplateInfoFieldMapper.batchInsert(approvalTemplateInfoFieldPOS);
        }
    }

    /**
     * 插入记录并获取ID
     *
     * @param approvalTemplate
     * @return ID
     */
    private Long insertApprovalTemplate(ApprovalTemplateDTO approvalTemplate) {
        ApprovalTemplatePO approvalTemplatePO = new ApprovalTemplatePO();
        CustomBeanUtil.copyProperties(approvalTemplate, approvalTemplatePO);
        approvalTemplateMapper.insert(approvalTemplatePO);
        return approvalTemplatePO.getId();
    }

    /**
     * 插入记录并获取ID
     *
     * @param node
     * @return ID
     */
    private Long insertApprovalTemplateNode(ApprovalTemplateNodeDTO node) {
        ApprovalTemplateNodePO approvalTemplateNodePO = new ApprovalTemplateNodePO();
        CustomBeanUtil.copyProperties(node, approvalTemplateNodePO);
        approvalTemplateNodeMapper.insert(approvalTemplateNodePO);
        return approvalTemplateNodePO.getId();
    }

    @Transactional
    private void updateApprovalTemplate(ApprovalTemplateDTO approvalTemplate) {
        Long approvalTemplateId = approvalTemplate.getId();
        ApprovalTemplatePO approvalTemplatePO = new ApprovalTemplatePO();
        CustomBeanUtil.copyProperties(approvalTemplate, approvalTemplatePO);
        approvalTemplateMapper.updateById(approvalTemplatePO);

        approvalTemplateNodeMapper.deleteByApprovalTemplateId(approvalTemplateId);
        approvalTemplateNodeAuditorMapper.deleteByApprovalTemplateId(approvalTemplateId);
        approvalTemplateInfoFieldMapper.deleteByApprovalTemplateId(approvalTemplateId);

        createTemplateWithId(approvalTemplateId, approvalTemplate);
    }

    @Override
    public void delete(ApprovalTemplateRequest request) {
        approvalTemplateMapper.deleteById(request.getApprovalTemplateId());
    }

    @Override
    public Rows<ApprovalTemplateDTO> list(ApprovalTemplateRequest request) {
        return null;
    }
}
